﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Runtime.Gateway;
using Phoenix.RedisConnectors;
using PServiceBus.Core.Interface;
using PServiceBus.Core.Security;
using PServiceBus.Gateway.Interfaces;
using PServiceBus.Gateway.Interfaces.DTO;
using PServiceBus.Gateway.Redis.DTO;
using PServiceBus.Gateway.Interfaces.Exceptions;
using PServiceBus.Core.Runtime;
using PServiceBus.Gateway.Redis.Commands;
using PServiceBus.Gateway.Interfaces.Commands;

namespace PServiceBus.Gateway.Redis {
    public class RedisMessageBus : GatewayMessageBusBase {

        public RedisMessageBus() { }

        static RedisMessageBus() {
            RedisSerializationBootstrapper.Configure();
            ServiceLocator<IBusRouter>.Set(new RedisBusRouter());
            ServiceLocator<IGatewayServer>.Set(new RedisGatewayServer());
            ServiceLocator<IGatewayClient>.Set(new RedisGatewayClient());
            ServiceLocator<IGatewayService>.Set(new RedisGatewayService());
            ServiceLocator<IRouterService>.Set(new RedisRouterService());
        }

        public RedisMessageBus(string address) : base(address) { }

        #region GatewayMessageBusBase Members
        public override IGatewayMessageBus Init(string address) {
            return new RedisMessageBus(address);
        }

        public override void CreateSubscriber(string subscriber, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(subscriberName: subscriber, async: false, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void ChangeSubscriberDurability(string subscriber, bool durable, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(subscriberName: subscriber, durable: durable, async: false, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void SubscribeTo(string subscriber, string topicName, string filter, bool needHeader, bool caseSensitive, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(subscriberName: subscriber,
            topicName: topicName, filter: filter, needHeader: needHeader, async: false, caseSensitive: caseSensitive, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void UpdateSubscriber(string subscriber, string topicName, string filter, bool needHeader, bool caseSensitive, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(subscriberName: subscriber,
            topicName: topicName, filter: filter, needHeader: needHeader, async: false, caseSensitive: caseSensitive, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void UnSubscribeFrom(string subscriber, string topicName, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(subscriberName: subscriber, topicName: topicName, async: false, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void AddTransport(string subscriber, string transportName, ITransport transport, string topicName, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(subscriberName: subscriber, transportName: transportName,
                transport: transport, topicName: topicName, async: false, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void DeleteTransport(string subscriber, string transportName, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(subscriberName: subscriber, transportName: transportName, async: false, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override SubscriberInfo SelectSubscriber(string name, Dictionary<string, string> headers) {
            return Send<RedisESBRequest, RedisSubscriberInfo>(RedisESBRequest.New(name, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override TopicInfo SelectTopic(string name, Dictionary<string, string> headers) {
            var response = Send<RedisESBRequest, RedisESBTopicInfo>(RedisESBRequest.New(name, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
            return response != null ? response.Topic : null;
        }

        public override void DeleteSubscriber(string name, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(subscriberName: name, async: false, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void RegisterTopic(TopicInfo topic, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(topic: topic, async: false, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void PublishTopic(TopicInfo topic, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(topic: topic, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override void DeleteTopic(string name, Dictionary<string, string> headers) {
            Send<BusMessage>(RedisBusMessage.New(topicName: name, async: false, userIdentity: Identity, reThrowException: ReThrowException, headers: Headers));
        }

        public override IList<TopicInfo> GetTopics(Dictionary<string, string> headers) {
            return Send<RedisESBRequest, RedisTopicInfos>(RedisESBRequest.New(userIdentity: Identity, reThrowException: ReThrowException, headers: Headers)).Topics;
        }

        public override bool IsValidException(Exception ex) {
            var exName = ex.GetType().Name;
            var isRedisException = exName.Contains("ZmqSocketException") || exName.Contains("ZmqException");
            if (!isRedisException && ex is RedisFaultException) 
                throw ex;
            return isRedisException;
        }
        #endregion
    }
}
